package tablekeylocal

import (
	"strings"
	"sync"

	"gitee.com/tomatomeatman/golang-repository/bricks2/function/data/integerutil"
	"gitee.com/tomatomeatman/golang-repository/bricks2/function/data/stringutil"
	"gitee.com/tomatomeatman/golang-repository/bricks2/model/dbinfo"
	"gitee.com/tomatomeatman/golang-repository/bricks2/utils/app"
	"gitee.com/tomatomeatman/golang-repository/bricks2/utils/gorm"
	Log "github.com/cihub/seelog"
)

var (
	createLock             = &sync.Mutex{}            //创建用锁
	syncTablekeyMap        = map[string]*sync.Mutex{} //序列锁集合
	syncCountTablekeyMap   = map[string]int{}         //序列锁引用计数值集合,当值为0时同时清理'序列锁集合'
	sDbName                string                     //数据库名
	tableKeyLocalTableName string                     //表名
)

func init() {
	tableKeyLocalTableName = app.ReadConfigKey("DbVariables", "TableKeyName", "TableKeyLocal").(string)

	sDbName = app.ReadConfigKey("DbVariables", "MainDb", "BaseSystem.").(string)
	if !strings.HasSuffix(sDbName, ".") {
		sDbName = sDbName + "."
	}
}

/**
 * 记录编号序列管理表TableKeyLocal表基本业务操作结构体
 */
type TableKeyLocalDao struct {
}

/**
 * 取各表(或序列)的新Id
 * @param formatLong 格式化长度(不足长度+0)
 * @param serieName 表名或序列名
 * @return
 */
func (o TableKeyLocalDao) GetNewId(formatLong int, serieName string) string {
	lock, ok := syncTablekeyMap[serieName]
	if !ok {
		createLock.Lock() //加锁
		lock = &sync.Mutex{}
		syncTablekeyMap[serieName] = lock
		syncCountTablekeyMap[serieName] = 1 //计数值
		createLock.Unlock()                 //解锁
	} else {
		syncCountTablekeyMap[serieName] = syncCountTablekeyMap[serieName] + 1 //计数值
	}

	lock.Lock()         //加锁
	defer lock.Unlock() //解锁

	iCount := o.newValue(serieName)
	if iCount != 1 {
		iCount = o.addTable(serieName)
		if iCount != 0 {
			syncCountTablekeyMap[serieName] = syncCountTablekeyMap[serieName] - 1 //计数值-1
			if syncCountTablekeyMap[serieName] < 1 {                              //计数值为0,剔除
				delete(syncCountTablekeyMap, serieName)
				delete(syncTablekeyMap, serieName)
			}

			return stringutil.SupplyZero(formatLong, 1)
		}

		syncCountTablekeyMap[serieName] = syncCountTablekeyMap[serieName] - 1 //计数值-1
		if syncCountTablekeyMap[serieName] < 1 {                              //计数值为0,剔除
			delete(syncCountTablekeyMap, serieName)
			delete(syncTablekeyMap, serieName)
		}

		return "0" //说明是取值失败
	}

	Id := o.findLastId(serieName)
	if Id == "0" {
		syncCountTablekeyMap[serieName] = syncCountTablekeyMap[serieName] - 1 //计数值-1
		if syncCountTablekeyMap[serieName] < 1 {                              //计数值为0,剔除
			delete(syncCountTablekeyMap, serieName)
			delete(syncTablekeyMap, serieName)
		}

		return "0" //说明是取值失败
	}

	syncCountTablekeyMap[serieName] = syncCountTablekeyMap[serieName] - 1 //计数值-1
	if syncCountTablekeyMap[serieName] < 1 {                              //计数值为0,剔除
		delete(syncCountTablekeyMap, serieName)
		delete(syncTablekeyMap, serieName)
	}

	result := stringutil.SupplyZero(formatLong, Id)

	return result
}

/**
 * 取各表的一批新Id
 * @param formatLong 格式化长度(不足长度+0)
 * @param serieName 表名或序列名
 * @param size 数量
 * @return
 */
func (o TableKeyLocalDao) GetNewIds(formatLong int, serieName string, size int) []string {
	lock, ok := syncTablekeyMap[serieName]
	if !ok {
		createLock.Lock() //加锁
		lock = &sync.Mutex{}
		syncTablekeyMap[serieName] = lock
		syncCountTablekeyMap[serieName] = 1 //计数值
		createLock.Unlock()                 //解锁
	} else {
		syncCountTablekeyMap[serieName] = syncCountTablekeyMap[serieName] + 1 //计数值
	}

	lock.Lock()         //加锁
	defer lock.Unlock() //解锁

	iCount := o.newValues(serieName, size)
	if iCount != 1 {
		iCount = o.addTableValues(serieName, size)
	}

	if iCount != 1 {
		syncCountTablekeyMap[serieName] = syncCountTablekeyMap[serieName] - 1 //计数值-1
		if syncCountTablekeyMap[serieName] < 1 {                              //计数值为0,剔除
			delete(syncCountTablekeyMap, serieName)
			delete(syncTablekeyMap, serieName)
		}

		return nil //说明是取值失败
	}

	sLastId := o.findLastId(serieName)

	syncCountTablekeyMap[serieName] = syncCountTablekeyMap[serieName] - 1 //计数值-1
	if syncCountTablekeyMap[serieName] < 1 {                              //计数值为0,剔除
		delete(syncCountTablekeyMap, serieName)
		delete(syncTablekeyMap, serieName)
	}

	iLastId := integerutil.ToInt(sLastId)

	result := []string{}
	for i := 0; i < size; i++ {
		vNewId := stringutil.SupplyZero(formatLong, iLastId+i+1)
		result = append(result, vNewId)
	}

	return result
}

/**
 * 重置
 * @param serieName 表名或序列名
 * @return
 */
func (o TableKeyLocalDao) Reset(serieName string) string {
	iCount := o.reset(serieName)

	if iCount < 1 {
		return "0"
	}

	return "1"
}

/**
 * 更新到新Value值
 * @param Type
 * @return
 */
func (o TableKeyLocalDao) newValue(serieName string) int {
	sql := "UPDATE ${BaseSystem}TableKeyLocal SET value = (value +1) ,edition = (edition +1) WHERE type = '#{type}'"
	sql = strings.Replace(sql, "${BaseSystem}", sDbName, -1)
	sql = strings.Replace(sql, "TableKeyLocal", tableKeyLocalTableName, -1)
	sql = strings.Replace(sql, "#{type}", serieName, -1)

	dbResult := gorm.Exec(sql)
	if dbResult.Error != nil {
		Log.Error("更新数据发生异常:", dbResult.Error)
		return 0
	}

	return integerutil.ToInt(dbResult.RowsAffected, 0)
}

/**
 * 取最后的id值
 * @param Value
 * @return
 */
func (o TableKeyLocalDao) findLastId(serieName string) string {
	sql := "SELECT value FROM ${BaseSystem}TableKeyLocal WHERE type = '#{type}'"
	sql = strings.Replace(sql, "${BaseSystem}", sDbName, -1)
	sql = strings.Replace(sql, "TableKeyLocal", tableKeyLocalTableName, -1)
	sql = strings.Replace(sql, "#{type}", serieName, -1)

	Value := "0"
	dbResult := gorm.Raw(sql).Find(&Value)
	if dbResult.Error != nil {
		Log.Error("更新数据发生异常:", dbResult.Error)
		return Value
	}

	return Value
}

/**
 * 添加表字段信息
 * @param serieName
 * @return
 */
func (o TableKeyLocalDao) addTable(serieName string) int {
	sql := `
	INSERT INTO ${BaseSystem}TableKeyLocal (
		id
		,type
		,value
		,index
		,edition
	)
	SELECT
		IFNULL(MAX(id), 0) +1
		,'#{type}'
		,'1'
		,1
		,1
	FROM ${BaseSystem}TableKeyLocal`
	sql = strings.Replace(sql, "${BaseSystem}", sDbName, -1)
	sql = strings.Replace(sql, "TableKeyLocal", tableKeyLocalTableName, -1)
	sql = strings.Replace(sql, "#{type}", serieName, -1)

	dbResult := gorm.Exec(sql)
	if dbResult.Error != nil {
		Log.Error("更新数据发生异常:", dbResult.Error)
		return 0
	}

	return integerutil.ToInt(dbResult.RowsAffected, 0)
}

/**
 * 更新到新的一批Value值
 * @param serieName
 * @param size
 * @return
 */
func (o TableKeyLocalDao) newValues(serieName string, size int) int {
	sql := `UPDATE ${BaseSystem}TableKeyLocal SET
				value = (value +1 + ${size})
				,edition = (edition +1 + ${size})
			WHERE type = #{type}`
	sql = strings.Replace(sql, "${BaseSystem}", sDbName, -1)
	sql = strings.Replace(sql, "TableKeyLocal", tableKeyLocalTableName, -1)
	sql = strings.Replace(sql, "${size}", stringutil.ToStr(size), -1)
	sql = strings.Replace(sql, "#{type}", serieName, -1)

	dbResult := gorm.Exec(sql)
	if dbResult.Error != nil {
		Log.Error("更新数据发生异常:", dbResult.Error)
		return 0
	}

	return integerutil.ToInt(dbResult.RowsAffected, 0)
}

/**
 * 添加表字段信息,并设置初始值
 * @param serieName
 * @param size
 * @return
 */
func (o TableKeyLocalDao) addTableValues(serieName string, size int) int {
	sql := `
	INSERT INTO ${BaseSystem}TableKeyLocal (
		id
		,type
		,value
		,index
		,edition
	)
	SELECT
		IFNULL(MAX(id), 0) +1
		,'#{type}'
		,#{size}
		,1
		,#{size}
	FROM ${BaseSystem}TableKeyLocal`
	sql = strings.Replace(sql, "${BaseSystem}", sDbName, -1)
	sql = strings.Replace(sql, "TableKeyLocal", tableKeyLocalTableName, -1)
	sql = strings.Replace(sql, "${size}", stringutil.ToStr(size), -1)
	sql = strings.Replace(sql, "#{type}", serieName, -1)

	dbResult := gorm.Exec(sql)
	if dbResult.Error != nil {
		Log.Error("更新数据发生异常:", dbResult.Error)
		return 0
	}

	return integerutil.ToInt(dbResult.RowsAffected, 0)
}

/**
 * 重置
 * @param serieName
 * @return
 */
func (o TableKeyLocalDao) reset(serieName string) int {
	sql := `UPDATE ${BaseSystem}TableKeyLocal SET
			value = 1
			,edition = (edition +1)
		WHERE type = '#{type}'`
	sql = strings.Replace(sql, "${BaseSystem}", sDbName, -1)
	sql = strings.Replace(sql, "TableKeyLocal", tableKeyLocalTableName, -1)
	sql = strings.Replace(sql, "#{type}", serieName, -1)
	sql = strings.Replace(sql, "edition", dbinfo.TableEdition[0], -1)

	dbResult := gorm.Exec(sql)
	if dbResult.Error != nil {
		Log.Error("更新数据发生异常:", dbResult.Error)
		return 0
	}

	return integerutil.ToInt(dbResult.RowsAffected, 0)
}
